import { waitFor } from 'next-test-utils'
import { outdent } from 'outdent'
import { isNextDev, nextTestSetup } from 'e2e-utils'

describe('app-fetch-deduping', () => {
  if (isNextDev) {
    describe('during next dev', () => {
      const { next } = nextTestSetup({ files: __dirname })
      function invocation(cliOutput: string): number {
        return cliOutput.match(/Route Handler invoked/g).length
      }

      it('should dedupe requests called from the same component', async () => {
        await next.patchFile(
          'app/test/page.tsx',
          outdent`
          async function getTime() {
            const res = await fetch("http://localhost:${next.appPort}/api/time")
            return res.text()
          }
          
          export default async function Home() {
            await getTime()
            await getTime()
            const time = await getTime()
          
            return <h1>{time}</h1>
          }`
        )

        await next.render('/test')

        expect(invocation(next.cliOutput)).toBe(1)
        await next.stop()
      })

      it('should dedupe pending revalidation requests', async () => {
        await next.start()
        const revalidate = 5
        await next.patchFile(
          'app/test/page.tsx',
          outdent`
          async function getTime() {
            const res = await fetch("http://localhost:${next.appPort}/api/time", { next: { revalidate: ${revalidate} } })
            return res.text()
          }
          
          export default async function Home() {
            await getTime()
            await getTime()
            const time = await getTime()
          
            return <h1>{time}</h1>
          }`
        )

        await next.render('/test')

        expect(invocation(next.cliOutput)).toBe(1)

        // wait for the revalidation to finish
        await waitFor(revalidate * 1000 + 1000)

        await next.render('/test')

        expect(invocation(next.cliOutput)).toBe(2)
      })
    })
  } else {
    it('should skip other scenarios', () => {})
    return
  }
})
